import 'dart:io';
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:fast_gbk/fast_gbk.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/services.dart';

class EBookReader extends StatefulWidget {
  @override
  State<EBookReader> createState() => _EBookReaderState();
}

class _EBookReaderState extends State<EBookReader> {
  bool _isLoading = false; // 加载判断
  String _fileContent = ''; // 文件展示内容
  List<List<int>>? allDataChunks; // 存储文件数据流分块
  List<String> deDataChunks=[]; // 存储解码的数据
  int pageCode = 0; // 页码
  bool isGbk = false; // 编码判断
  late String path; // 路经
  late int pageSizeInBytes; // 数据流分块大小

  late ScrollController _scrollController;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _scrollController = ScrollController();
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); // 隐藏所有系统 UI 元素
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _scrollController.dispose();
    // 恢复系统 UI
    SystemChrome.setEnabledSystemUIMode(
      SystemUiMode.edgeToEdge,
      overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom],
    );
  }


  Future<void> _pickFile() async {
    // 打开文件选择器
    FilePickerResult? result = await FilePicker.platform.pickFiles(
      type: FileType.custom,
      allowedExtensions: ['txt'], // 只允许选择 .txt 文件
    );

    if (result != null) {
      setState(() {
        _isLoading = true; // 开始加载
        _fileContent = ''; // 重置文件内容
      });
      path = result.files.single.path!;
      File file = File(path); // 获取文件路径
      isGbk = checkFileWithEncoding(file);
      try {
        // 读取文件内容
        await _initReadFileAsync(file);
      } catch (e) {
        // 捕获并处理异常
        setState(() {
          _fileContent = 'Error reading file: $e';
          _isLoading = false;
        });
      }
    } else {
      // 用户取消选择
      print("User canceled the picker");
    }
  }


  bool checkFileWithEncoding(File file) {

    bool checkGarbled(String content) {
      final garbledPattern = RegExp(r'Õ|Ê|Ç|³|¾|Ð|Ó|Î|Á|É|�');

      final lines = content.split('\n');

      final sampleLines = lines.take(lines.length > 10 ? 10 : lines.length);
      return sampleLines.any((line) => garbledPattern.hasMatch(line));
    }

    final List<Encoding> encodings = [
      utf8,
      latin1,
    ];

    for (final encoding in encodings) {
      try {
        final content = file.readAsStringSync(encoding: encoding);

        if (!checkGarbled(content)) {
          return false;
        }
      } catch (e) {
        continue;
      }
    }

    try {
      final _ = gbk.decode(file.readAsBytesSync());
      return true;
    } catch (e) {
      return false;
    }
  }

  // 读取文件的某个范围返回
  Future<List<List<int>>?> displayFileInPages(File file, int pageSizeBytes) async {
    if (!file.existsSync()) return null;

    final totalSize = file.lengthSync();
    int start = 0;
    int bufferSize = pageSizeBytes;

    List<List<int>> chunks = [];

    if(isGbk){
      // 算了，这种写法太麻烦了！
      final input = file.openRead();
      var buffer = <int>[];

      await for (final chunk in input) {
        buffer.addAll(chunk);

        while (buffer.length >= pageSizeBytes) {
          // 寻找最佳分割点
          final splitPos = _findBestSplitPosition(buffer, pageSizeBytes);

          chunks.add(buffer.sublist(0, splitPos));

          // 保留剩余部分
          buffer = buffer.sublist(splitPos);
        }
      }

      // 添加最后剩余的部分
      if (buffer.isNotEmpty) {
        chunks.add(buffer);
      }

      return chunks;
    }else{
      Utf8Decoder decoder = Utf8Decoder();
      List<int> buffer = [];

      while (start < totalSize) {
        int end = start + bufferSize;
        if (end > totalSize) end = totalSize;

        // 读取当前块
        final chunk = await file.openRead(start, end).first;
        buffer.addAll(chunk);

        // 尝试解码并找到有效的 UTF-8 边界
        int validEnd = buffer.length;
        while (validEnd > 0) {
          try {
            decoder.convert(buffer.sublist(0, validEnd)); // 尝试解码
            break; // 如果没有抛出异常，则找到了有效的边界
          } catch (e) {
            if (e is FormatException) {
              validEnd--; // 尝试缩短边界，直到找到有效的 UTF-8 序列
            } else {
              rethrow; // 其他异常重新抛出
            }
          }
        }

        // 保存有效数据块（如果 validEnd 为 0，则保存空块或跳过）
        if (validEnd > 0) {
          chunks.add(buffer.sublist(0, validEnd));
          buffer = buffer.sublist(validEnd); // 保留未处理的字节到下一次循环
        }

        start += bufferSize; // 注意：这里的 start 只是用于循环控制，实际读取由 buffer 控制
      }

      // 如果还有剩余的字节，作为最后一个块添加
      if (buffer.isNotEmpty) {
        chunks.add(buffer);
      }
    }

    return chunks;
  }

  // GBK 辅助工具
  int _findBestSplitPosition(List<int> bytes, int targetSize) {
    // 优先在目标位置分割（如果是ASCII字符）
    if (targetSize < bytes.length && bytes[targetSize] <= 0x7F) {
      return targetSize;
    }

    // 向前查找最近的ASCII字符
    for (int i = targetSize - 1; i >= 0; i--) {
      if (bytes[i] <= 0x7F) {
        return i + 1; // 在ASCII字符后分割
      }
    }

    // 如果没有ASCII字符，检查GBK字符边界
    for (int i = targetSize - 1; i >= 1; i--) {
      // 如果是GBK字符的第二字节
      if (bytes[i] >= 0x40 && bytes[i] <= 0xFE &&
          bytes[i-1] >= 0x81 && bytes[i-1] <= 0xFE) {
        return i + 1; // 在完整GBK字符后分割
      }
    }

    // 实在找不到安全点，强制在目标位置分割
    return targetSize.clamp(0, bytes.length);
  }

  Future<void> decodeDataChunks(List<List<int>> dataChunks) async {
    deDataChunks = []; // 初始化
      if (isGbk) {
        // 使用 fast_gbk 解码 GBK
        for (var dataChunk in dataChunks){
          deDataChunks.add(gbk.decode(dataChunk));
        }
      } else {
        // 默认使用 UTF-8 解码
        for (var dataChunk in dataChunks){
          deDataChunks.add(utf8.decode(dataChunk));
        }
      }
  }

  Future<void> _initReadFileAsync(File file) async {
    pageSizeInBytes = 4096; // 每页读取至少 1024 字节
    allDataChunks = await displayFileInPages(file, pageSizeInBytes);
    if (allDataChunks != null) {

      await decodeDataChunks(allDataChunks!);
      if (deDataChunks.isNotEmpty) {
        setState(() {
          _fileContent = deDataChunks[0]; // 显示第一页内容
          _isLoading = false;
        });
      }
    } else {
      setState(() {
        _fileContent = 'Failed to read file.';
        _isLoading = false;
      });
    }
  }

  Future<void> prePage() async {
    if (pageCode > 0) {
      pageCode--;
      setState(() {
        _fileContent = deDataChunks[pageCode];
      });
    }
    _scrollToTop();
  }

  Future<void> nextPage() async {
    if (pageCode < (deDataChunks.length) - 1) {
      pageCode++;
      setState(() {
        _fileContent = deDataChunks[pageCode];
      });
    }
    _scrollToTop();
  }

  bool _isScrolling = false;
  void _scrollToTop() async {
    if (_isScrolling) return; // 防止重复调用
    _isScrolling = true;

    await _scrollController.animateTo(
      0.0,
      duration: Duration(milliseconds: 30),
      curve: Curves.easeOut,
    );
    _isScrolling = false;
  }

  late bool _showAppBar = true; // 控制 AppBar 是否显示
  void _toggleAppBar() {
    setState(() {
      _showAppBar = !_showAppBar; // 切换 AppBar 显示状态
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _showAppBar?
      AppBar(
        title: Text('无记录阅读器', style: TextStyle(fontSize: 15)),
        toolbarHeight: 44, // 调整工具栏高度以适应内容
        automaticallyImplyLeading: false, // 关闭自动生成的返回箭头
        actions: [
          TextButton(
            onPressed: _pickFile,
            child: Text('选择一个txt文件'),
          ),
        ],
      ) : null,
      body: GestureDetector(
        onTap: _toggleAppBar,
        child: Column(
          children: [
            if(!_showAppBar)
              SizedBox(height: 40,),
            if (_isLoading)
              LinearProgressIndicator(), // Show a loading indicator
            Expanded(
              child: SingleChildScrollView(
                controller: _scrollController,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    children: [
                      Text(
                        _fileContent.isEmpty ? 'No file selected' : _fileContent,
                        style: TextStyle(fontSize: 22),
                      ),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          TextButton(
                            onPressed: pageCode > 0 ? prePage : null,
                            child: Text("上一部分",style: TextStyle(fontSize: 22),),
                          ),
                          TextButton(
                            onPressed: pageCode < (deDataChunks.length) - 1 ? nextPage : null,
                            child: Text("下一部分",style: TextStyle(fontSize: 22),),
                          ),
                        ],
                      )
                    ],
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}